/*
 * Copyright (c) 2011 Joe Kopena <tjkopena@gmail.com>
 *
 * Permission is hereby granted, free of charge, to any person
 * obtaining a copy of this software and associated documentation
 * files (the "Software"), to deal in the Software without
 * restriction, including without limitation the rights to use, copy,
 * modify, merge, publish, distribute, sublicense, and/or sell copies
 * of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be
 * included in all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
 * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
 * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
 * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
*/

package com.rocketshipgames.haxe.physics;

import com.rocketshipgames.haxe.Entity;

enum BoundsBehavior {
  BOUNDS_NONE;
  BOUNDS_DETECT;
  BOUNDS_STOP;
}

class ShooterPhysicsPackage {

  public var xvel:Float;
  public var xacc:Float;
  public var xdrag:Float;

  public var yvel:Float;
  public var yacc:Float;
  public var ydrag:Float;

  public var xvelMin:Float;
  public var xvelMax:Float;

  public var yvelMin:Float;
  public var yvelMax:Float;

  private var _boundsCheckType:BoundsBehavior;

  private var _x1:Float;
  private var _y1:Float;

  private var _x2:Float;
  private var _y2:Float;

  public var offBoundsLeft:Void->Void;
  public var offBoundsRight:Void->Void;
  public var offBoundsTop:Void->Void;
  public var offBoundsBottom:Void->Void;

  private var _parent:Entity;

  //------------------------------------------------------------------
  public function new(parent:Entity):Void
  {
    _parent = parent;

    xvel = xacc = xdrag = 0;
    yvel = yacc = ydrag = 0;

    xvelMin = xvelMax = 0;
    yvelMin = yvelMax = 0;

    _boundsCheckType = BOUNDS_NONE;
    offBoundsLeft = null;
    offBoundsRight = null;
    offBoundsTop = null;
    offBoundsBottom = null;

    // end ShooterPhysicsPackage
  }

  public function parent():Entity { return _parent; }

  //------------------------------------------------------------------
  public function update():Void 
  {

    var elapsed:Float = World.elapsed/1000.0;

    //-------
    // x
    if (xacc == 0) {
      // trace("xacc 0");
      if (xvel > 0) {
	xvel -= xdrag * elapsed;
	if (xvel < 0)
	  xvel = 0;
      } else {
	xvel += xdrag * elapsed;
	if (xvel > 0)
	  xvel = 0;
      }
    } else  {
      xvel += xacc * elapsed;
      // trace("xacc not 0---" + xacc + "; min " + xvelMin +"; " + xvel);
      if (Math.abs(xvel) < xvelMin) {
	// trace("abs");
	xvel = 0;
      } else if (xvel < -xvelMax)
	xvel = -xvelMax;
      else if (xvel > xvelMax)
	xvel = xvelMax;
    }

    // y
    if (yacc == 0) {
      if (yvel > 0) {
	yvel -= ydrag * elapsed;
	if (yvel < 0)
	  yvel = 0;
      } else {
	yvel += ydrag * elapsed;
	if (yvel > 0)
	  yvel = 0;
      }
    } else {
      yvel += yacc * elapsed;
      if (Math.abs(yvel) < yvelMin)
	yvel = 0;
      else if (yvel < -yvelMax)
	yvel = -yvelMax;
      else if (yvel > yvelMax)
	yvel = yvelMax;
    }


    _parent.x += xvel*elapsed;
    _parent.y += yvel*elapsed;

    checkBounds();

    // end update
  }

  public function setBounds(?type:BoundsBehavior=null,
			    ?x1:Float = 0,
			    ?y1:Float = 0,
			    ?x2:Float = 0,
			    ?y2:Float = 0):Void
  {
    if (type == null) type = BOUNDS_NONE;
    if (x2 == 0) x2 = World.rectangle.width;
    if (y2 == 0) y2 = World.rectangle.height;

    _x1 = Math.min(x1, x2);
    _x2 = Math.max(x1, x2);

    _y1 = Math.min(y1, y2);
    _y2 = Math.max(y1, y2);

    _boundsCheckType = type;

    trace("Bounds set to " + _x1 + "," + _y1 + "  " + _x2 + "," + _y2);

    // end setBounds
  }


  private function checkBounds():Void
  {

    if (_boundsCheckType != BOUNDS_NONE) {

      if (_parent.x < _x1) {
	if (_boundsCheckType == BOUNDS_STOP) {
	  _parent.x = _x1;
	  xvel = 0;
	}

	if (offBoundsLeft != null)
	  offBoundsLeft();

	// end x off left
      } else if (_parent.x > _x2) {
	if (_boundsCheckType == BOUNDS_STOP) {
	  _parent.x = _x2;
	  xvel = 0;
	}

	if (offBoundsRight != null)
	  offBoundsRight();

	// end x off right
      }

      if (_parent.y < _y1) {
	if (_boundsCheckType == BOUNDS_STOP) {
	  _parent.y = _y1;
	  yvel = 0;
	}

	if (offBoundsTop != null)
	  offBoundsTop();

	// end y off top
      } else if (_parent.y > _y2) {
	if (_boundsCheckType == BOUNDS_STOP) {
	  _parent.y = _y2;
	  yvel = 0;
	}

	if (offBoundsBottom != null)
	  offBoundsBottom();
	// end y off bottom
      }

      // end do bounds check
    }

    // end checkBounds
  }

  // end class ShooterPhysicsPackage
}
